package middleware

import (
	"app/common/constant"
	"app/internal/model"
	"app/pkg/config"
	"app/pkg/jwt"
	"app/pkg/log"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// JwtMiddleware jwt中间件
func JwtMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		//从请求头中获取token
		tokenStr := c.Request.Header.Get("Authorization")
		//用户不存在
		if tokenStr == "" {
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "请登录"})
			c.Abort() //阻止执行
			return
		}
		//token格式错误
		tokenSlice := strings.SplitN(tokenStr, " ", 2)
		if len(tokenSlice) != 2 && tokenSlice[0] != "Bearer" {
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "登录凭证格式错误"})
			c.Abort() //阻止执行
			return
		}
		//验证token
		tokenStruck, ok := jwt.CheckToken(tokenSlice[1], config.Config.App.JwtSignKey)
		if !ok {
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "登录状态已失效"})
			c.Abort() //阻止执行
			return
		}
		//token超时
		if time.Now().Unix() > tokenStruck.ExpiresAt {
			c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "登录已过期"})
			c.Abort() //阻止执行
			return
		}
		var user model.UserModel
		uri := c.Request.RequestURI
		user, err := model.FindOne[model.UserModel](map[string]interface{}{"id": tokenStruck.Uid})
		if err != nil {
			log.NewError("login-verify", err, fmt.Sprintf("%+v", tokenStruck))
			c.JSON(http.StatusOK, gin.H{"code": constant.LoginFailed, "msg": "用户数据错误"})
			c.Abort() //阻止执行
			return
		}
		if user.State == 2 {
			c.JSON(http.StatusOK, gin.H{"code": constant.LoginFailed, "msg": "账号已被封禁"})
			c.Abort() //阻止执行
			return
		}
		if user.State == 3 {
			c.JSON(http.StatusOK, gin.H{"code": constant.LoginFailed, "msg": "账号已注销"})
			c.Abort() //阻止执行
			return
		}
		if strings.Index(uri, "/manager/") == 0 {
			if user.Type != 2 {
				c.JSON(http.StatusOK, gin.H{"code": constant.LogicError, "msg": "暂无权限访问"})
				c.Abort() //阻止执行
				return
			}
		}
		c.Set("uid", tokenStruck.Uid)     //用户ID
		c.Set("username", user.Username)  //用户名
		c.Set("phone", user.Phone)        //用户名
		c.Set("pass_salt", user.PassSalt) //密码salt
		c.Set("userModel", user)          //userModel
		c.Next()
	}
}
